package com.applet.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *   封装 HttpClient的工具类
 *   用来发送get/post请求的
 *                              尽量解耦合，少用第三方工具jar，减少本工具类迁移成本
 */
public class HttpClientUtil {
    private HttpClientUtil(){}

    //连接超时时间(单位毫秒)
    private static final int CONNECT_TIMEOUT = 7000;
    //从连接池获取http请求对象的超时时间(单位毫秒)  没有连接池则不用设置
    private static final int CONNECTION_REQUEST_TIMEOUT = 7000;
    //读取超时，表示从请求的网址处获得响应数据的时间间隔(单位毫秒)
    private static final int SOCKET_TIMEOUT = 7000;

    // 请求的一些配置  公共使用，如果请求需要特殊设置，请在方法中自定义
    private static RequestConfig requestConfig = RequestConfig.custom()
            //设置连接超时时间(单位毫秒) ，3次握手
            .setConnectTimeout(CONNECT_TIMEOUT)
            //从连接池获取http请求对象的超时时间(单位毫秒)
            //.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
            //读取超时，表示从请求的网址处获得响应数据的时间间隔(单位毫秒)
            .setSocketTimeout(SOCKET_TIMEOUT)
            //设置是否允许重定向(默认为true)
            .setRedirectsEnabled(true)
            .build();




    /**
     * Get请求  --  无参   返回的Json数据
     */
    public static String doGetNoParamsResponseJson(String url){
        // 返回字符串
        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Get请求对象  设置请求url
        HttpGet httpGet = new HttpGet(url);

        // 3.设置请求的一些参数
        httpGet.setConfig(requestConfig);
        // 请求头 ....


        // 响应返回的对象
        CloseableHttpResponse response = null;

        try {
            // 4.执行请求
            response = httpClient.execute(httpGet);

            // 5.解析返回数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--Get(无参)请求--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpClient关闭失败");
                }
            }
        }

        return resultStr;
    }




    /**
     * Get请求  --  有参   返回来的Json数据
     */
    public static String doGetHasParamsResponseJson(String url, Map<String, String> paramMap){
        //返回字符串
        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 响应对象
        CloseableHttpResponse response = null;

        try {
            // 2.创建封装参数的builder对象   并设置请求url
            URIBuilder builder = new URIBuilder(url);

            // 3.添加参数
            if( !CollectionUtils.isEmpty(paramMap) ){
                paramMap.forEach((key, value) -> builder.addParameter(key, value));
            }

            // 4.构建uri对象
            URI uri = builder.build();

            // 5.创建HttpGet请求对象
            HttpGet httpGet = new HttpGet(uri);

            // 6.请求的一些配置信息
            httpGet.setConfig(requestConfig);
            // 6.1添加请求头中的数据

            // 7.执行请求
            response = httpClient.execute(httpGet);

            // 8.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, Consts.UTF_8);
            } else {
                System.out.println(url + "--get(有参)请求--接口返回错误信息: " + EntityUtils.toString(response.getEntity(), Consts.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpclient关闭失败");
                }
            }
        }

        return resultStr;
    }




    /**
     *                                    Content-type: application/json
     * Post请求  --  有参   响应的Json数据
     */
    public static String doPostJsonHasParamsResponseJson(String url, Map<String, String> paramMap){

        // 返回的字符串
        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些配置
        httpPost.setConfig(requestConfig);
        // 添加请求头
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");


        // 4.判断参数是否为空
        if( !CollectionUtils.isEmpty(paramMap) ){
            // 5.不为空 封装json入参
            StringEntity httpEntity = new StringEntity(JSON.toJSONString(paramMap, SerializerFeature.WriteMapNullValue), StandardCharsets.UTF_8);
            // 5.1设置请求方式
            httpEntity.setContentType(ContentType.APPLICATION_JSON.toString());
            // 5.2设置编码
            httpEntity.setContentEncoding(StandardCharsets.UTF_8.toString());
            // 封装
            httpPost.setEntity(httpEntity);
        }


        // 响应返回的对象
        CloseableHttpResponse response = null;

        try {
            // 6.执行请求
            response = httpClient.execute(httpPost);

            // 7.解析响应数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);

            } else {
                System.out.println(url + "[json]--post(有参)请求--接口返回错误信息: " + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpClient关闭失败");
                }
            }
        }

        return resultStr;
    }





    /**
     *                                    Content-type: application/x-www-form-urlencoded  表单提交(不涉及File)
     * Post请求  --  有参    响应的Json数据
     */
    public static String doPostSimpleFormHasParamsResponse(String url, Map<String, String> paramMap){
        // 返回的字符串
        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些参数
        httpPost.setConfig(requestConfig);

        // 4.请求类型
        httpPost.addHeader("Content-type", "application/x-www-form-urlencoded");

        // 5.封装body数据
        List<NameValuePair> inputList = new ArrayList<>();
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                inputList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        // 6.创建表单对象 并 设置字符集
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(inputList, StandardCharsets.UTF_8);

        // 7.将表单数据设置到post请求中
        httpPost.setEntity(formEntity);


        // 响应对象
        CloseableHttpResponse response = null;

        try {
            // 8.执行请求
            response = httpClient.execute(httpPost);

            // 9.解析响应数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--[x-www-form-urlencoded]-post请求(有参)--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(httpClient != null){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpClient关闭失败");
                }
            }
        }

        return resultStr;
    }




    /**
     *                                    Content-type: multipart/form-data  表单提交(包括File)
     * Post请求  --  有参    响应的Json数据
     */
    public static String doPostFormFileHasParamsResponseJson(String url, String fileName, MultipartFile file, Map<String,String> paramMap){
        // 返回字符串
        String resultStr = null;

        // 1.创建HttpClient，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些参数
        httpPost.setConfig(requestConfig);

        // 4.请求类型
        httpPost.addHeader("Content-type", "multipart/form-data");

        // 5.构造File文件上传使用的entity
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        // 6.请求类型
        builder.setContentType(ContentType.create("multipart/form-data", StandardCharsets.UTF_8));
        // 7.设置编码
        builder.setCharset(StandardCharsets.UTF_8);
        // 8.设置为 浏览器上传模式(解决返回中文乱码问题)
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

        // 9.封装File文件IO流参数
        try {
            builder.addBinaryBody(fileName, file.getInputStream(), ContentType.create("multipart/form-data"), file.getOriginalFilename());
        } catch (IOException e) {
            System.out.println(url + "--post(有参)请求--[form-data]--封装File文件参数异常");
            e.printStackTrace();
        }

        // 10.添加表单中<input>标签的字段值    类似浏览器表单提交，对应input的name和value
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                // addTextBody(k, v) ---> v是中文则乱码 -->  addTextBody(k, v, ContentType.create("text/plain", HTTP.UTF_8))
                builder.addPart(entry.getKey(), new StringBody(entry.getValue(), ContentType.create(HTTP.PLAIN_TEXT_TYPE, Consts.UTF_8)));
            }
        }

        // 11.构建httpEntity参数对象
        HttpEntity httpEntity = builder.build();
        // 12.设置参数到post请求对象中
        httpPost.setEntity(httpEntity);


        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 13.执行post请求
            response = httpClient.execute(httpPost);

            // 14.解析相应数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--[form-data]-post请求(有参)--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpClient关闭失败");
                }
            }
        }

        return resultStr;
    }







}
